import bootstrap
import datetime
import inspect
import sys
import os

from multiprocessing.queues import Queue
from multiprocessing.pool import Pool
from multiprocessing import Process
import multiprocessing
import itertools

import generate_weights

from aisbx import platform, callstack
from game import application

def run(args):
    try:
        level, commanders, q = args
        sys.stderr.write('.')
        runner = platform.ConsoleRunner()
        runner.accelerate()
        app = application.CaptureTheFlag(list(commanders), level, quiet = True, games = 1)
        runner.run(app)
        sys.stderr.write('o')
        q.put("%s %s\n" % (level, app.scores))
        return level, app.scores
    except Exception as e:
        print >> sys.stderr, str(e)
        tb_list = callstack.format(sys.exc_info()[2])
        for s in tb_list:
            print >> sys.stderr, s
        raise
    except KeyboardInterrupt:
        return None 

def write_to_file(q):
    now = datetime.datetime.now()
    path = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
    f = open('%s/logs/competition_log_%s.txt' % (path, now.strftime("%Y-%m-%d %H%M")), 'w')
    while True:
        f.write(q.get())
        f.flush()
        q.task_done()

if __name__ == '__main__':
    p = Pool(processes = multiprocessing.cpu_count())
    q = multiprocessing.Manager().Queue()
    write_process = Process(target=write_to_file, args=(q,))
    write_process.start()
    
    pairs = itertools.permutations(['tactics.NNCommander1', 'tactics.NNCommander2', 'tactics.NNCommander3', 'tactics.NNCommander4', 'examples.Balanced' ], 2)
    # games = list(itertools.product(['map00', 'map01', 'map10', 'map11', 'map20', 'map21', 'map30'], pairs, [q]))
    games = list(itertools.product(['map00', 'map20'], pairs, [q]))
    generation_num = 0
    while generation_num < 1000:
        total = 0
        scores = {}    
        for map, results in p.map(run, games):
            for bot, score in results.items():
                print bot, score
                b = bot[1]
                scores.setdefault(b, [0, 0])
                scores[b][0] += score[0]
                scores[b][1] += score[1]
            total += 1

        print "\n%i total games run." % (total)
        q.put("\n%i total games run.\n" % (total))
        sorted_scores = sorted(scores.items(), key = lambda i: (-i[1][0]+i[1][1], i[1][1]))
        sorted_nn = []
        for r, s in sorted_scores:
            bot = r
            print "{}   for: {}, against: {}".format(bot.replace('Commander', '').upper(), s[0], s[1])
            q.put("{}   for: {}, against: {}\n".format(bot.replace('Commander', '').upper(), s[0], s[1]))
            if bot.startswith('NN'):
                sorted_nn.append('%s.dump' % bot)
        generate_weights.mutate_population([sorted_nn[0], sorted_nn[1]], [sorted_nn[2], sorted_nn[3]], 'evolution.dump')
        generation_num += 1
    q.join()
    write_process.terminate()
